/**
 * Copyright (C) 2015-2018 IQIYI
 * All rights reserved.
 *
 * Author     : 王海斌
 * E-mail     : wanghaibin@qiyi.com
 * Version    :
 * Date       : Wed 27 May 2020 01:48:50 PM CST
 * Destription:  测试孙子继承时成员变量访问
 *
 *              结论
 *              1. 菱形继承当根类有成员变量时必须采用虚继承
 *              2. 子类析构函数中的this地址和父类虚函数中的this地址是不同的
 *              3. dynamic_pointer_cast<A>(B)和dynamic_cast<A>(B)转换后的指针地址是<>内A对象的地址,不是()内B对象的地址
 *              4. 通过dynamic_pointer_cast<A>(B) 转换后的对象调用reset不能修改B的内容
 */
#include <iostream>
#include <stdio.h>
#include <memory>

class base
{
public:
    base (){ data_ = 3;}
    virtual ~base () { printf("base this=%p\n", this);}
protected:
    int data_;
};

class child : virtual public base
{
public:
    child () {datac_ = 1; }
    virtual ~child () {
        base * tmp_base = dynamic_cast<base*>(this);
        printf("child addr=%p, dynamic_cast<base*>(this)=%p\n", this, tmp_base);
    }

protected:
    int  datac_;
};

class childB : virtual public base
{
public:
    childB () {}
    virtual ~childB () {}

};

class classC : public base
{
public:
    classC() {}
    virtual ~classC () {}
};

class grandson_diamond : public child
                         ,public childB
{ //菱形继承
public:
    grandson_diamond () {}
    virtual ~grandson_diamond () {}

public:
    int get_grandpa() {
        return data_;
    }
};
class grandson : public child
{
public:
    grandson () {}
    virtual ~grandson () {
        child * tmp_child = dynamic_cast<child*>(this);
        base * tmp_base = dynamic_cast<base*>(this);
        printf("grandson addr=%p, dynamic_cast<child*>(this)=%p, dynamic_cast<base*>(this)=%p\n", this, tmp_child, tmp_base);}

public:
    int get_grandpa() {
        return data_;
    }
};

void test_cast_fun(std::shared_ptr<base> new_base, std::shared_ptr<classC> &child) {
    printf("new_base.count=%d, child.count=%d\n", new_base.use_count(), child.use_count());
    new_base.reset();
    printf("after new_base.reset new_base.count=%d, child.count=%d, new_base=%s \n", new_base.use_count(), child.use_count(), NULL==new_base?"NULL":"NOT_NULL");
}
/**
 * @brief 测试通过dynamic_pointer_cast转后调用reset对原始数据的影响
 *
 */
void test_dynamic_pointer_cast_reset() {
    auto c = std::make_shared<classC>();
    printf("dynamic_pointer_cast 前 child.count=%d\n", c.use_count());
    test_cast_fun(std::dynamic_pointer_cast<base>(c), c);
    printf("执行 reset 后 child=%s, c.count=%d\n", c==NULL?"NULL":"NOT NULL", c.use_count());
}

int main(int , char *[])
{

    test_dynamic_pointer_cast_reset();
    return 0;
    grandson gs;
    grandson_diamond gs2;
    printf("测试1:\n测试显说明子类析构函数中的this地址和父类析构函数中的this值不同\n");
    {
        child gs_tmp;
    }
    {
        auto c = std::make_shared<child>();
        std::shared_ptr<base> b = std::dynamic_pointer_cast<base>(c);
        printf("\n\n测试2:\ndynamic_pointer_cast转换后的内容中的指针地址%p, 转换前地址=%p\n", b.get(), c.get());
    }
    printf("\n\ngs value=%d, diamon value=%d\n", gs.get_grandpa(), gs2.get_grandpa());
    return 0;
}
